/*******************************************************************************
  * @file                   main.c
  * @Author:                MQjehovah                 mail:MQjehovah@hotmail.com
  * @version                1.0.0
  * @date                   2017.12.23
  * @brief                  
  ******************************************************************************
  * @attention
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "BSP.h"
#include "shell.h"
/* Definition ----------------------------------------------------------------*/
typedef void (*iapfun)(void); //定义一个函数类型的参数.
iapfun jump2app;
/* Functions -----------------------------------------------------------------*/
/*******************************************************************************
  * @brief  时钟配置            
  * @param  None              
  * @retval None              
  * @Note   None              
*******************************************************************************/
void RCC_Config()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
}

/*******************************************************************************
  * @brief  中断优先级配置            
  * @param  None              
  * @retval None              
  * @Note   None              
*******************************************************************************/
void NVIC_Config(void) //配置中断优先级
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    //	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;				//使能按键所在的外部中断通道
    // 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2，
    //	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;			//子优先级1
    //	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道
    //	NVIC_Init(&NVIC_InitStructure);
}

/*******************************************************************************
  * @brief  等待用户按下一个键              
  * @param  timeout：超时时间              
  * @retval 0：未按下
            1：按下
  * @Note   None              
*******************************************************************************/
u8 Waiting_Key(u8 timeout)
{
    u32 start = 0;
    while (timeout--)
    {
        SHELL_SendStr("\rpress any key into bootloader  ");
        SHELL_SendChar(timeout + 0x30);

        start = sys_Time;
        while (sys_Time - start < 1000)
        {
            if (pSHELL_RX_BUF->lenth > 0)
            {
                SHELL_SendStr("\rJUMPING INTO BOOTLOADER......        \r\n");
                RingBuf_flush(pSHELL_RX_BUF);
                return 1;
            }
        }
    }
    SHELL_SendStr("\rJUMPING INTO APPLICATION......            \r\n");
    return 0;
}

/*******************************************************************************
  * @brief  跳转到用户程序              
  * @param  None    
  * @retval None
  * @Note   None              
*******************************************************************************/
u8 JUMP_TO_USERAPP(u32 appaddr)
{
    if (((*(vu32 *)(appaddr + 4)) & 0xFF000000) == 0x08000000) //判断是否为0X08XXXXXX.
    {
        if (((*(vu32 *)appaddr) & 0x2FFE0000) == 0x20000000) //检查栈顶地址是否合法.
        {
            __disable_irq();
            __set_MSP(*(vu32 *)appaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
            (*(void (*)(void))(*(vu32 *)(appaddr + 4)))();
        }
    }
    return 0;
}

/*******************************************************************************
  * @brief  主函数              
  * @param  None              
  * @retval None              
  * @Note   None              
*******************************************************************************/
int main(void)
{
    NVIC_Config(); //配置中断优先级
    RCC_Config();
    SysTick_init(); //初始化延时函数
    LED_Init();     //初始化LED
    USART_Config(USART1, 115200);
    // debug_init(115200);                                 //调试串口
    SHELL_SendStr("                  \r\n"); //清除E34模块上电乱码
    SHELL_SendStr("                  \r\n");
    SHELL_SendStr(" _                 _   _                 _\r\n");
    SHELL_SendStr("| |__   ___   ___ | |_| | ___   __ _  __| | ___ _ __\r\n");
    SHELL_SendStr("| '_ \\ / _ \\ / _ \\| __| |/ _ \\ / _` |/ _` |/ _ \\ '__|\r\n");
    SHELL_SendStr("| |_) | (_) | (_) | |_| | (_) | (_| | (_| |  __/ |\r\n");
    SHELL_SendStr("|_.__/ \\___/ \\___/ \\__|_|\\___/ \\__,_|\\__,_|\\___|_|\r\n");
    SHELL_SendStr("\r\n"); //留白
    if (Waiting_Key(5))
    {
        shell_loop();
    }
    if (!JUMP_TO_USERAPP(APPLICATION_ADDRESS))
    {
        SHELL_SendStr("error app addr\r\n");
        SHELL_SendStr("jump into bootloader\r\n");
        shell_loop();
    }
}
/*********************************END OF FILE**********************************/
